package com.yang.spring.core.bean.builder;

import com.yang.spring.core.bean.BeanFactory;
import com.yang.spring.core.bean.definition.BeanDefinition;
import com.yang.spring.core.utils.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class AbstractBeanBuilder implements IBeanBuilder {
    @Override
    public Object buildBean(BeanDefinition beanDefinition) throws InstantiationException, IllegalAccessException, InvocationTargetException {
        List<BeanDefinition> dependencyBeanDefinitionList = beanDefinition.getDependencyBeanDefinitionList();
        if (CollectionUtils.isNotEmpty(dependencyBeanDefinitionList)) {
            // 构造依赖的bean
            for (BeanDefinition dependencyBeanDefinition : dependencyBeanDefinitionList) {
                Object dependencyInstance = BeanFactory.getBeanByName(dependencyBeanDefinition.getBeanName(), dependencyBeanDefinition.getBeanClassType());
                if (dependencyInstance == null) {
                    dependencyInstance = BeanFactory.buildBeanInstance(dependencyBeanDefinition);
                }
                dependencyBeanDefinition.setInstance(dependencyInstance);
            }
        }
        Class beanClassType = beanDefinition.getBeanClassType();
        Object instance = beanClassType.newInstance();
        beanDefinition.setInstance(instance);
        richBeanDefinition(beanDefinition);
        BeanFactory.putBean(beanDefinition, instance);
        return instance;
    }

    protected void richBeanDefinition(BeanDefinition beanDefinition) throws IllegalAccessException {
        Class beanClassType = beanDefinition.getBeanClassType();
        Field[] declaredFields = beanClassType.getDeclaredFields();
        Map<String, Field> fieldName2DeclaredFieldMap = new HashMap<>();
        for (Field declaredField : declaredFields) {
            fieldName2DeclaredFieldMap.put(declaredField.getName(), declaredField);
        }
        for (Map.Entry<String, BeanDefinition> entry : beanDefinition.getDependencyBeanName2BeanDefinitionMap().entrySet()) {
            String dependencyBeanName = entry.getKey();
            BeanDefinition dependencyBeanDefinition = entry.getValue();
            Field field = fieldName2DeclaredFieldMap.get(dependencyBeanName);
            if (field == null) {
                return;
            }
            field.setAccessible(true);
            field.set(beanDefinition.getInstance(), dependencyBeanDefinition.getInstance());
        }
    }
}